package cnu.cse.crawler.manager;

import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.StringTokenizer;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import cnu.cse.crawler.xedata.XeAttachedFile;
import cnu.cse.crawler.xedata.XeBoard;
import cnu.cse.crawler.xedata.XeDocument;

public class PageParsingManager 
{
	///////////////////////////////////////////// Member /////////////////////////////////////////////
	//
	//
	
	private static PageParsingManager instance = new PageParsingManager();

	private static final int DOCUMNET_COMBINING_INIT_INDEX = 38;
	private static final int DOCUMENT_COMBINING_UNIT = 24;
	private static final int ATTACHEDFINE_COMBINING_UNIT = 9;
	
	
	
	
	
	
	////////////////////////////////// Constructor and Initializer ///////////////////////////////////
	//
	//
	
	private PageParsingManager()
	{
		
	}
	
	public static PageParsingManager getInstance()
	{
		return instance;
	}
	
	
	
	
	
	
	//////////////////////////////////////// Private Methods ////////////////////////////////////////
	//
	//
		
	private int parseJavascriptArray(ArrayList<String> list, String javascriptArray, int start)
	{
		int index = start;
		boolean isProcessed = false;
				
		String value = "";
		
		if (javascriptArray.charAt(index) == '"')
		{
			index++;
			while (true)
			{
				if (javascriptArray.charAt(index) == '"'
						&& (javascriptArray.charAt(index+1) == ',' || javascriptArray.charAt(index+1) == ']'))
				{
					index += 2;
					isProcessed = true;
					break;
				}
				
				value += javascriptArray.charAt(index);
				index++;
			}
		}
		
		if (javascriptArray.charAt(index) == '\'')
		{
			index++;
			while (true)
			{
				if (javascriptArray.charAt(index) == '\''
						&& (javascriptArray.charAt(index+1) == ',' || javascriptArray.charAt(index+1) == ']'))
				{
					index += 2;
					isProcessed = true;
					break;
				}
				
				value += javascriptArray.charAt(index);
				index++;
			}
		}
				
		if (isProcessed == false)
		{
			while (true)
			{				
				if (javascriptArray.charAt(index) == ',' || javascriptArray.charAt(index) == ']')
				{
					index++;
					break;
				}
				
				value += javascriptArray.charAt(index);
				index++;
			}
		}
		
		list.add(value);
				
		return index;
	}
	
	
	
	
	
	
	//////////////////////////////////////// Public Methods ////////////////////////////////////////
	//
	//
	
	public XeBoard createBoardFromBoardHtml(String baseUrl, String boardPath, String boardHtml) throws UnsupportedEncodingException 
	{ 
		Document doc = Jsoup.parse(boardHtml);
		
		Element boardInfoElement = doc.getElementsByClass("al").get(1);
		String boardInfo = boardInfoElement.ownText().replace("\u00A0", "$"); // no-break space (&bbsp;) to $

		StringTokenizer st1 = new StringTokenizer(boardInfo, "$");
		StringTokenizer st2 = new StringTokenizer(st1.nextToken(), "/");
		st2.nextToken();
		String boardDocumentCount = st2.nextToken().replace(" ", "");
		StringTokenizer st3 = new StringTokenizer(st1.nextToken(), "/");
		st3.nextToken();
		String boardPageCount = st3.nextToken().replace(" ", "");
		
		XeBoard result = new XeBoard(baseUrl, boardPath, Integer.parseInt(boardPageCount), Integer.parseInt(boardDocumentCount));
		
		Element pageListElement = doc.getElementsByClass("pcenter").get(0);
		Elements pages = pageListElement.getElementsByTag("a");
		
		String firstPage = pages.get(0).attr("href");
		result.addPagePath(firstPage);
		
		for (Element page : pages)
		{
			if (page.children().isEmpty())
			{
				result.addPagePath(page.attr("href"));
			}			
		}
				
		return result;
	}
		
	public void addDocumentsOfEachPageIntoBoard(XeBoard board, String boardPageHtml) throws UnsupportedEncodingException
	{ 		
		String javascriptArray = "";
		
		Document doc = Jsoup.parse(boardPageHtml);
		Element itemList = doc.getElementsByTag("script").get(2);
		
		//
		// preprocessing phase
		javascriptArray = itemList.html();
		javascriptArray = javascriptArray.replace("<!--var Posts=", "");
		javascriptArray = javascriptArray.replace("_post_ltop(Posts);-->", "");
		
		//
		// parsing phase
		ArrayList<String> intermediateResult = new ArrayList<String>();		
		int parsingIndex = 0;
		
		while (parsingIndex < javascriptArray.length()-1)
		{
			if (javascriptArray.charAt(parsingIndex) == '\t'
				|| javascriptArray.charAt(parsingIndex) == ' '
				|| javascriptArray.charAt(parsingIndex) == '['
				|| javascriptArray.charAt(parsingIndex) == ']'
				|| javascriptArray.charAt(parsingIndex) == ',')
			{
				parsingIndex++;
			}
			else
			{
				parsingIndex = parseJavascriptArray(intermediateResult, javascriptArray, parsingIndex);
			}
		}
				
		//
		// combining phase
		int combiningIndex = DOCUMNET_COMBINING_INIT_INDEX;
		// initial index == 38, combining unit == 24
		// index + 1  == document number
		// index + 2  == comment count
		// index + 4  == type (:tic: == normal, :tic:new: == newest, :not:tic: == notice, :del:tic: == delete, :loc:tic: == complete) 
		// index + 5  == url
		// index + 7  == contents summary
		// index + 13 == date(YYYY/MM/DD)
		// index + 14 == time(HH:mm:SS)
		// index + 16 == update count
		// index + 17 == writer ID
		// index + 18 == writer nickname
		// index + 22 == title
		
		while (combiningIndex < intermediateResult.size())
		{
			int number = Integer.parseInt(intermediateResult.get(combiningIndex + 1));	
			
			int commentCount = Integer.parseInt(intermediateResult.get(combiningIndex + 2));
			
			int type;
			if (intermediateResult.get(combiningIndex + 4).equals(":not:tic:"))
			{
				type = XeDocument.TYPE_NOTICE;
			}
			else if (intermediateResult.get(combiningIndex + 4).equals(":loc:tic:"))
			{
				type = XeDocument.TYPE_LOCKED;
			}
			else if (intermediateResult.get(combiningIndex + 4).equals(":del:tic:"))
			{
				type = XeDocument.TYPE_DELETED;
			}
			else if (intermediateResult.get(combiningIndex + 4).equals(":tic:"))
			{
				type = XeDocument.TYPE_NORMAL;
			}
			else if (intermediateResult.get(combiningIndex + 4).equals(":tic:new:"))
			{
				type = XeDocument.TYPE_NEWEST;
			}
			else
			{
				type = XeDocument.TYPE_UNKNOWN;
			}
						
			String path = intermediateResult.get(combiningIndex + 5);
			
			String contentsSummary = intermediateResult.get(combiningIndex + 7);
			
			String date = intermediateResult.get(combiningIndex + 13).replace("/", "");
			
			String time = intermediateResult.get(combiningIndex + 14).replace(":", "");
			
			int updateCount = Integer.parseInt(intermediateResult.get(combiningIndex + 16));
			
			String writerId = intermediateResult.get(combiningIndex + 17);
			
			String writerNickname = intermediateResult.get(combiningIndex + 18);
			
			String title = intermediateResult.get(combiningIndex + 22);
			
			// create xe document
			XeDocument xeDoc = new XeDocument(number, path, type, title, date, time, writerId, writerNickname, commentCount, updateCount, contentsSummary);
			board.addDocument(xeDoc);
			
			combiningIndex += DOCUMENT_COMBINING_UNIT;
		}
	
	}
	
	public void addContentsIntoDocument(XeDocument document, String documentHtml)
	{				
		Document doc = Jsoup.parse(documentHtml);

		// IP address
		Element ipInfoElement = doc.getElementsByClass("atext").first();
		String ip = ipInfoElement.attr("title");
		ip = ip.replace("IP:", "");
		document.setIpAddress(ip);
				
		// contents
		Element contentsDiv = doc.getElementsByClass("context_view").first();
		String contents = contentsDiv.html();
		
		document.setContents(contents);
		
		// attached files
		Element attachedFileInfoElement = doc.getElementsByTag("script").get(1);
		String attachedFileInfo = attachedFileInfoElement.html();
		attachedFileInfo = attachedFileInfo.replace("<!--var ImageWidthFit = '500';", "");
		attachedFileInfo = attachedFileInfo.replace("-->", "");
		
		StringTokenizer st = new StringTokenizer(attachedFileInfo, ";");
		attachedFileInfo = st.nextToken();
		attachedFileInfo = attachedFileInfo.replace("var PostFiles = ", "");
		
		//
		// parsing phase
		ArrayList<String> intermediateResult = new ArrayList<String>();		
		int parsingIndex = 0;
		
		while (parsingIndex < attachedFileInfo.length()-1)
		{
			if (attachedFileInfo.charAt(parsingIndex) == '\t'
				|| attachedFileInfo.charAt(parsingIndex) == ' '
				|| attachedFileInfo.charAt(parsingIndex) == '['
				|| attachedFileInfo.charAt(parsingIndex) == ']'
				|| attachedFileInfo.charAt(parsingIndex) == ',')
			{
				parsingIndex++;
			}
			else
			{
				parsingIndex = parseJavascriptArray(intermediateResult, attachedFileInfo, parsingIndex);
			}
		}
		
		//
		// combining phase
		int combiningIndex = 0;
		// initial index == 0, combining unit == 9
		// index + 0  == attached file name
		// index + 2  == attached file path
		
		while (combiningIndex < intermediateResult.size())
		{
			String sourceFileName = intermediateResult.get(combiningIndex);
			String sourceFilePath = intermediateResult.get(combiningIndex + 2);
			String datetime = document.getDate() + document.getTime();
			String ipAddress = document.getIpAddress();
			
			document.addAttachedFile(new XeAttachedFile(sourceFileName, sourceFilePath, datetime, ipAddress));
			
			combiningIndex += ATTACHEDFINE_COMBINING_UNIT;
		}
	}
	
	public void GenerateXeDocumentFromDocumentHtml(String documentHtml)
	{
		System.out.println();
		System.out.println(">>> parsing for board document html");
		
		Document doc = Jsoup.parse(documentHtml);
		
		// title
		Element titleDiv = doc.getElementsByClass("read_title").first();
		String title = titleDiv.ownText();
				
		// writer, ip, date, count
		Elements spanElements = doc.getElementsByClass("text");
		Element writerSpan = spanElements.get(0);
		Element dateSpan = spanElements.get(1);
		Element ipA = dateSpan.child(0);
		Element countSpan = spanElements.get(2);
		
		String writer = writerSpan.ownText();
		String ip = ipA.attr("title");
		ip = ip.replace("IP:", "");
		String date = ipA.ownText() + dateSpan.ownText();
		date = date.replace(":", "");
		date = date.replace("/", "");
		String count = countSpan.ownText();
		count = count.replace("조회:", "");
		
		// contents summary
		Element contentsDiv = doc.getElementsByClass("context_view").first();
		String contents = contentsDiv.html();
				
		System.out.println("Title: " + title);
		System.out.println("Writer: " + writer);
		System.out.println("IP: " + ip);
		System.out.println("Date: " + date);
		System.out.println("Count: " + count);
		
		Element fileInfo = doc.getElementsByTag("script").get(1);
		String javascript = fileInfo.html();
		javascript = javascript.replace("<!--var ImageWidthFit = '500';", "");
		javascript = javascript.replace("-->", "");
		
		
		StringTokenizer st = new StringTokenizer(javascript, ";");
		String javascriptFileInfo = st.nextToken();
		String javascriptDocumentNumber = st.nextToken();
		
		javascriptFileInfo = javascriptFileInfo.replace("var PostFiles = ", "");
		javascriptDocumentNumber = javascriptDocumentNumber.replace("var POST_ID=", "[") + "]";
		
		System.out.println(javascriptFileInfo);
		System.out.println(javascriptDocumentNumber);
		
		ArrayList<String> result = new ArrayList<String>();
		
		int index = 0;
		while (index < javascriptFileInfo.length()-1)
		{
			if (javascriptFileInfo.charAt(index) == '\t'
					|| javascriptFileInfo.charAt(index) == ' '
					|| javascriptFileInfo.charAt(index) == '['
					|| javascriptFileInfo.charAt(index) == ']'
					|| javascriptFileInfo.charAt(index) == ',')
			{
				index++;
			}
			else
			{
				index = parseJavascriptArray(result, javascriptFileInfo, index);
			}
		}
		
		index = 0;
		while (index < javascriptDocumentNumber.length()-1)
		{
			if (javascriptDocumentNumber.charAt(index) == '\t'
					|| javascriptDocumentNumber.charAt(index) == ' '
					|| javascriptDocumentNumber.charAt(index) == '['
					|| javascriptDocumentNumber.charAt(index) == ']'
					|| javascriptDocumentNumber.charAt(index) == ',')
			{
				index++;
			}
			else
			{
				index = parseJavascriptArray(result, javascriptDocumentNumber, index);
			}
			
		}
		
	}
	
	
	
}
